#include "StdAfx.h"
#include "SystemDllCacher.h"

using namespace Adaptive::Foundation;
using namespace Adaptive::Foundation::IO;

/*--------------------------------------------------------------------------------
 * Constructor / Dispose / Destructor Methods
 *------------------------------------------------------------------------------*/
#pragma region Constructor / Dispose / Destructor Methods
// <summary>
// Initializes a new instance of the class.
// </summary>
// <remarks>
// This is the default constructor.
// </remarks>
SystemCacher::SystemCacher()
{
	_cancelFlag = false;
	_progress = 0;
}
// <summary>
// Class destructor.
// </summary>
SystemCacher::~SystemCacher()
{
	_cancelFlag = false;
	_progress = 0;
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Public Properties
 *------------------------------------------------------------------------------*/
#pragma region Public Properties
// <summary>
// Gets the current progress percentage value.
// </summary>
// <value>
// A progress percentage value.
// </value>
int SystemCacher::Progress::get()
{
    return _progress;
}
#pragma endregion

/*--------------------------------------------------------------------------------
 * Protected Methods / Event Methods
 *------------------------------------------------------------------------------*/
#pragma region Protected Methods / Event Methods
// <summary>
// Raises the <see cref="ProgressUpdate"/> event.
// </summary>
// <param name="e">An <see cref="EventArgs"/> event arguments instance.</param>
void SystemCacher::OnProgressUpdate(EventArgs^ e)
{
	ProgressUpdate(this, e);
}

#pragma endregion

/*--------------------------------------------------------------------------------
 * Public Methods / Event Methods
 *------------------------------------------------------------------------------*/
#pragma region Protected Methods / Event Methods
// <summary>
// Cancels the current caching operation.
// </summary>
// <remarks>
// If an operation is in progress, calling this method will cause the operation to terminate.  
// This is included for asynchronous calls.
// </remarks>
void SystemCacher::Cancel()
{
	_cancelFlag = true;
}
// <summary>
// Caches the system32 DLLs into memory.
// </summary>
// <remarks>
// This causes the class to load the DLLs in the Windows system directory to memory.  This operation
// may be stopped by calling the <see cref="Cancel"/> method.
// </remarks>
void SystemCacher::CacheSystemDlls()
{
	StringCollection^ list = nullptr;		//List of files to be loaded.
	String^ item = nullptr;					//Individual item name.
	int count = 0;							//Iteration counter.
	int length = 0;							//Iteration limit.

	//Get the DLL list.
	list = GetSystemDlls();
	length = list->Count;

	//Iterate through the list until the end is reached, or 
	// the operation is canceled.
	while ((count < length) && (!_cancelFlag))
	{
		//Load the DLL.
		item = list[count];
		LoadDll(item);

		//Set progress value.
		_progress = (int)(((float)count / length)*100);
		count++;

		//Raise event every 5 items for speed purposes.
		if (count % 5 == 0)
			OnProgressUpdate(EventArgs::Empty);
	}

	//Clear memory.
	list->Clear();
	delete(list);
	list = nullptr;
	item = nullptr;
}
// <summary>
// Loads a specific DLL into memory.
// </summary>
// <param name="dllName">The fully-qualified path and name of the DLL to be cached.</param>
// <remarks>
// Caches the specified DLL into memory.
// </remarks>
void SystemCacher::LoadDll(String^ dllName)
{
	CString dllPathAndName;					//Native string.
	HMODULE moduleHandle = NULL;			//Handle to DLL.

	//Convert to a native string.
	dllPathAndName = dllName;
	try
	{
		//Attempt to load the library via API.
		moduleHandle = ::LoadLibrary(dllPathAndName);

		//This is required to prevent a crash when too many calls to the method are made
		// too quickly.
		Sleep(1);
	}
	catch(...)
	{
		moduleHandle = NULL;
	}

	// If the library was successfully loaded, unload it; it will remain in the system cache.
	if (moduleHandle != NULL)
	{
		try
		{
			FreeLibrary(moduleHandle);
		}
		catch(...)
		{
		}
		moduleHandle = NULL;
	}
}
// <summary>
// Gets a list of the DLLs in the system Win32 directory.
// </summary>
// <returns>
// A <see cref="StringCollection"/> instance containing the list of files names
// for all the DLLs in the Windows system directory.
// </returns>
StringCollection^ SystemCacher::GetSystemDlls()
{
	wchar_t *buffer = NULL;						//System directory name buffer.
	UINT size = 0;								//Buffer size.
	System::String^ system32;					//Converted string value.
	array<String^>^ files = nullptr;			//File list.
	StringCollection^ returnValue = nullptr;	//Return value.

	//Query Win api for system directory and convert to a string.
	buffer = new wchar_t[2048];
	size = 2048;
	::GetSystemDirectory(buffer, size);
	system32 = gcnew System::String(buffer);

	//Get the list of DLLs.
	try
	{
		files = System::IO::Directory::GetFiles(system32, "*.dll");
	}
	catch(...)
	{
		files = nullptr;
	}

	//Copy results to string collection.
	returnValue = gcnew StringCollection();
	if (files != nullptr)
	{
		
		returnValue->AddRange(files);

		//Clear.
		Array::Clear(files, 0, files->Length);
		delete(files);
		files = nullptr;
	}

	//Clear memory.
	delete(buffer);
	buffer = NULL;
	delete(system32);
	system32 = nullptr;

	return returnValue;
}
#pragma endregion
